package com.jingbit.ai.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import com.jingbit.ai.AIApp;
import com.jingbit.ai.bean.MsgBean;
import com.jingbit.ai.helper.GJsonHelper;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpService extends Service {
    public static final int MSG_CODE = 2000;
    private static final int CONN_ERR = -1;//-1连接失败
    private static final int CONN_INIT = 0;//0 常规
    private static final int CONN_ING = 1;//1连接中
    private static final int CONN_ED = 2;//2连接成功

    @Override
    public IBinder onBind(Intent intent) {
        return new TcpBinder();
    }

    public class TcpBinder extends Binder {

        private final int mHeart_spacetime = 1000; //心跳间隔时间
        private BufferedInputStream bis;
        private BufferedOutputStream bos;
        private ReadThread mReadThread;
        private final Handler mHandler = new Handler();
        private Socket mSocket;
        private ExecutorService mExecutorService;
        private int tryCount = 0;//重试次数
        private Handler.Callback listener;
        private volatile int status = CONN_INIT;//-1连接失败，0 常规，1连接中，2连接成功

        public void setCallback(Handler.Callback listener) {
            this.listener = listener;
        }

        public void startConnect() {
            //在子线程进行网络操作
            // Service也是运行在主线程，千万不要以为Service意思跟后台运行很像，就以为Service运行在后台子线程
            if (mExecutorService == null) {
                mExecutorService = Executors.newCachedThreadPool();
            }
            mExecutorService.execute(connectRunnable);
        }

        private final Runnable connectRunnable = new Runnable() {
            @Override
            public void run() {
                if (status >= CONN_ING) {
                    return;
                }
                try {
                    status = CONN_ING;
                    // 建立Socket连接
                    if (mSocket == null) {
                        Log.d(AIApp.TAG, "run: mSocket");
                        mSocket = new Socket();
                    }
                    mSocket.connect(new InetSocketAddress(AIApp.SOCKET_URL, AIApp.SOCKET_PORT), 1000);
                    if (bis == null) {
                        Log.d(AIApp.TAG, "run: bis");
                        bis = new BufferedInputStream(mSocket.getInputStream());
                    }
                    if (bos == null) {
                        Log.d(AIApp.TAG, "run: bos");
                        bos = new BufferedOutputStream(mSocket.getOutputStream());
                    }

                    // 创建读取服务器心跳的线程
                    if (mReadThread == null) {
                        mReadThread = new ReadThread();
                        mReadThread.start();
                    }
                    //开启心跳,每隔1秒钟发送一次心跳
                    mHandler.post(mHeartRunnable);
                    tryCount = 1;
                    Log.d(AIApp.TAG, "Socket连接建立");
                    status = CONN_ED;
                } catch (Exception e) {
                    e.printStackTrace();
                    tryCount++;
                    status = CONN_ERR;
                    Log.d(AIApp.TAG, "Socket连接建立失败,正在尝试第" + tryCount + "次重连");
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mExecutorService.execute(connectRunnable);
                        }
                    }, mHeart_spacetime * 3);
                }
            }
        };

        public class ReadThread extends Thread {
            @Override
            public void run() {
                int size;
                byte[] buffer = new byte[1024];
                try {
                    while ((size = bis.read(buffer)) != -1) {
                        String str = new String(buffer, 0, size);
                        Log.d(AIApp.TAG, "我收到来自服务器的消息: " + str);
                        MsgBean msgBean = null;
                        try {
                            msgBean = GJsonHelper.parseJson(str, MsgBean.class);
                        } catch (Exception e) {
                        }
                        if (msgBean != null) {
                            if (msgBean.getCode() == 1000) {
                                //收到心跳消息以后，首先移除断连消息，然后创建一个新的60秒后执行断连的消息。
                                //这样每次收到心跳后都会重新创建一个60秒的延时消息，在60秒后还没收到心跳消息，表明服务器已死，就会执行断开Socket连接
                                //在60秒钟内如果收到过一次心跳消息，就表明服务器还活着，可以继续与之通讯。
                                mHandler.removeCallbacks(disConnectRunnable);
                                mHandler.postDelayed(disConnectRunnable, mHeart_spacetime * 40);
                            }
                            if (listener != null && msgBean.getCode() != 1000) {
                                Message msg = Message.obtain();
                                msg.what = MSG_CODE;
                                msg.obj = msgBean;
                                listener.handleMessage(msg);
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        private final Runnable mHeartRunnable = new Runnable() {
            @Override
            public void run() {
                MsgBean msgBean = new MsgBean();
                msgBean.setCode(1000);
                sendData(msgBean);
            }
        };

        private void sendData(MsgBean data) {
            mExecutorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        bos.write(GJsonHelper.toJson(data).getBytes());
                        //一定不能忘记这步操作
                        bos.flush();
                        //发送成功以后，重新建立一个心跳消息
                        if (data.getCode() == 1000)
                            mHandler.postDelayed(mHeartRunnable, mHeart_spacetime);
                        Log.d(AIApp.TAG, "我发送给了服务器的消息: ");
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.d(AIApp.TAG, "心跳任务发送失败，正在尝试第" + tryCount + "次重连");
                        //mExecutorService.schedule(connectRunnable,mHeart_spacetime, TimeUnit.SECONDS);
                        mExecutorService.execute(connectRunnable);
                    }
                }
            });
        }

        private final Runnable disConnectRunnable = new Runnable() {
            @Override
            public void run() {
                disConnect();
            }
        };

        private void disConnect() {
            mExecutorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Log.d(AIApp.TAG, "正在执行断连: disConnect");
                        //执行Socket断连
                        mHandler.removeCallbacks(mHeartRunnable);
                        if (mReadThread != null) {
                            mReadThread.interrupt();
                            mReadThread = null;
                        }

                        if (bos != null) {
                            bos.close();
                            bos = null;
                        }

                        if (bis != null) {
                            bis.close();
                            bis = null;
                        }

                        if (mSocket != null) {
                            mSocket.shutdownInput();
                            mSocket.shutdownOutput();
                            mSocket.close();
                            mSocket = null;
                        }
                        status = CONN_INIT;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

